﻿using SqlSugar;
using System.Collections.Concurrent;
using System.Security.Cryptography;
using YY.Admin.Core.Session;
using YY.Admin.Core.Util;
using YY.Admin.Services.Service.Config;
namespace YY.Admin.Services.Service.Auth
{
    public class SysAuthService : ISysAuthService, ISingletonDependency
    {
        /// <summary>
        ///token过期时间(分)
        /// </summary>
        private const int _refreshUctExpires = 30;
        private SysUser? _currentUser;
        public SysUser? CurrentUser => _currentUser;
        public event EventHandler<SysUser?>? UserChanged;
        private readonly ISysCacheService _sysCacheService;
        private readonly ISqlSugarClient _dbContext;
        private readonly ISysConfigService _sysConfigService;
        private readonly IEventAggregator _eventAggregator;
        public SysAuthService(
            ISqlSugarClient dbContext,
            ISysCacheService sysCacheService,
            ISysConfigService sysConfigService,
            IEventAggregator eventAggregator) {
            _dbContext=dbContext;
            _sysCacheService=sysCacheService;
            _sysConfigService=sysConfigService;
            _eventAggregator = eventAggregator;
        }
        // 添加Token存储
        private static readonly ConcurrentDictionary<string, UserContext> _tokenStore =
            new ConcurrentDictionary<string, UserContext>();

        public async Task<LoginOutput> LoginAsync(LoginInput request)
        {
            try
            {
                // 判断密码错误次数（缓存30分钟）
                var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{request.Username}";
                var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
                var passwordMaxErrorTimes = await _sysConfigService.GetConfigValue<int>(ConfigConst.SysPasswordMaxErrorTimes);
                if (passwordMaxErrorTimes < 1) passwordMaxErrorTimes = 10;
                if (passwordErrorTimes > passwordMaxErrorTimes) {
                 
                    return new LoginOutput
                    {
                        Success = false,
                        Message = "密码错误次数过多，账号已锁定，请半小时后重试！"
                    };
                }
                // 账号是否存在
                var user = await _dbContext.Queryable<SysUser>().Includes(u => u.SysOrg).ClearFilter()
                    .WhereIF(request.TenantId > 0, u => u.AccountType == AccountTypeEnum.SuperAdmin || u.TenantId == request.TenantId)
                    .WhereIF(!string.IsNullOrWhiteSpace(request.Username), u => u.Account.Equals(request.Username) || u.Phone.Equals(request.Username))
                    .FirstAsync();
                if (user == null)
                {
                    return new LoginOutput
                    {
                        Success = false,
                        Message = "用户名或者密码不正确"
                    };
                }
                // 账号是否被冻结
                if (user.Status == StatusEnum.Disable)
                {
                    return new LoginOutput
                    {
                        Success = false,
                        Message = "账号已冻结"
                    };
                };

                if (VerifyPassword(request.Password, keyPasswordErrorTimes, passwordErrorTimes, user))
                {
                    _currentUser = user;
                    UserChanged?.Invoke(this, _currentUser);
                    return new LoginOutput
                    {
                        Success = true,
                        Message = "登录成功",
                        User = _currentUser,
                        Token =await GenerateToken(user)
                    };
                }
                else {
                    return new LoginOutput
                    {
                        Success = false,
                        Message = "用户名或者密码不正确！"
                    };
                }
            }
            catch (Exception ex)
            {
                return new LoginOutput
                {
                    Success = false,
                    Message = $"登录失败：{ex.Message}"
                };
            }
        }
        /// <summary>
        ///密码验证
        /// </summary>
        /// <param name="password"></param>
        /// <param name="keyPasswordErrorTimes"></param>
        /// <param name="passwordErrorTimes"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public bool VerifyPassword(string password, string keyPasswordErrorTimes, int passwordErrorTimes, SysUser user)
        {
            if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
            {
                if (user.Password.Equals(CryptogramUtil.Encrypt(password)))return true;
            }
            else
            {
                if (CryptogramUtil.Decrypt(user.Password).Equals(password)) return true;
            }
            _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
            return false;
        }
        public async Task<bool> IsAuthenticatedAsync()
        {
            await Task.Delay(50);
            return _currentUser != null;
        }
        /// <summary>
        ///创建token
        /// </summary>
        /// <returns></returns>
        private async Task<UserToken> GenerateToken(SysUser user)
        {
            user.LastLoginIp =await DeviceInfoUtil.GetPublicIpAddressAsync();
            //(user.LastLoginAddress, double? longitude, double? latitude) = CommonUtil.GetIpAddress(user.LastLoginIp);
            user.LastLoginTime = DateTime.Now;
            user.LastLoginDevice = DeviceInfoUtil.GetOsVersion();
            await _dbContext.Updateable(user).UpdateColumns(u => new
            {
                u.LastLoginIp,
                //u.LastLoginAddress,
                u.LastLoginTime,
                u.LastLoginDevice,
            }).ExecuteCommandAsync();
            _eventAggregator.GetEvent<LoginUserEvent>().Publish(user);

            // 生成访问令牌（实际项目应使用JWT）
            var accessToken = GenerateSecureToken(32);
            var refreshToken = GenerateSecureToken(32);
            var refreshExpiration = DateTime.UtcNow.AddMinutes(_refreshUctExpires);
            // 存储Token关联信息
            _tokenStore[accessToken] = new UserContext
            {
                UserId = user.Id,
                IsSuperAdmin = user.AccountType == AccountTypeEnum.SuperAdmin,
                Account= user.Account,
                AccountType = user.AccountType,
                OrgId= user.OrgId,
                RealName = user.RealName,
                TenantId= user.TenantId!.Value,
                Token=new UserToken() { 
                RefreshToken = refreshToken,
                RefreshUctExpires = refreshExpiration,
                }
            };
            return new UserToken
            {
                AccessToken = accessToken,
                RefreshToken = refreshToken,
                RefreshUctExpires = refreshExpiration
            };
        }
        private string GenerateSecureToken(int length)
        {
            using var rng = RandomNumberGenerator.Create();
            var tokenData = new byte[length];
            rng.GetBytes(tokenData);
            return Convert.ToBase64String(tokenData);
        }

        /// <summary>
        /// 实现Token验证
        /// </summary>
        /// <param name="accessToken"></param>
        /// <returns></returns>
        public bool ValidateToken(string accessToken)
        {
            if (string.IsNullOrEmpty(accessToken))
                return false;

            return _tokenStore.TryGetValue(accessToken, out var tokenInfo) &&
                   tokenInfo.Token.RefreshUctExpires > DateTime.UtcNow;
        }
        /// <summary>
        /// 实现刷新Token
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="refreshToken"></param>
        /// <returns></returns>
        public async Task<RefreshTokenResult> RefreshToken(string accessToken, string refreshToken)
        {
            if (!_tokenStore.TryGetValue(accessToken, out var tokenInfo) ||
                tokenInfo.Token.RefreshToken != refreshToken ||
                tokenInfo.Token.RefreshUctExpires < DateTime.UtcNow)
            {
                return new RefreshTokenResult { Success = false };
            }

            // 获取用户信息
            var user = await _dbContext.Queryable<SysUser>()
                .Where(u => u.Id == tokenInfo.UserId)
                .FirstAsync();

            if (user == null)
                return new RefreshTokenResult { Success = false };

            // 生成新Token
            var newToken = GenerateSecureToken(32);
            var newRefreshToken = GenerateSecureToken(32);

            // 更新Token存储
            _tokenStore.TryRemove(accessToken, out _);
            _tokenStore[newToken] = new UserContext
            {
                UserId = user.Id,
                IsSuperAdmin = user.AccountType == AccountTypeEnum.SuperAdmin,
                Account = user.Account,
                AccountType = user.AccountType,
                OrgId = user.OrgId,
                RealName = user.RealName,
                TenantId = user.TenantId!.Value,
                Token = new UserToken()
                {
                    RefreshToken = refreshToken,
                    RefreshUctExpires = DateTime.UtcNow.AddMinutes(_refreshUctExpires),
                }
            };

            return new RefreshTokenResult
            {
                Success = true,
                AccessToken = newToken,
                RefreshToken = newRefreshToken
            };
        }

        /// <summary>
        /// 增强退出登录实现
        /// </summary>
        /// <returns></returns>
        public async Task LogoutAsync()
        {
            if (_currentUser != null)
            {
                // 移除关联的Token
                var tokensToRemove = _tokenStore
                    .Where(kvp => kvp.Value.UserId == _currentUser.Id)
                    .Select(kvp => kvp.Key)
                    .ToList();

                foreach (var token in tokensToRemove)
                {
                    _tokenStore.TryRemove(token, out _);
                }
            }
            AppSession.CurrentUser = null; // 更新静态会话
            _currentUser = null;
            UserChanged?.Invoke(this, null);
            await Task.Delay(1000);
        }
    }
}
